# iOS版本文件扫描工具
# 使用Kivy框架实现，适配iOS设备特性

import os
import sys
import threading
import sqlite3
import time
from datetime import datetime
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.textinput import TextInput
from kivy.uix.popup import Popup
from kivy.uix.filechooser import FileChooserListView
from kivy.uix.modalview import ModalView
from kivy.core.window import Window
from kivy.uix.checkbox import CheckBox
from kivy.properties import StringProperty, BooleanProperty
from kivy.clock import Clock
from kivy.lang import Builder
from plyer import filechooser, clipboard
import shutil
import platform

# 设置窗口大小为iOS手机常见尺寸
Window.size = (375, 667)

# 支持中文显示
os.environ['KIVY_TEXT'] = 'pil'

# 定义文件项组件
class FileItem(RecycleDataViewBehavior, GridLayout):
    index = None
    file_name = StringProperty('')
    file_path = StringProperty('')
    file_size = StringProperty('')
    file_date = StringProperty('')
    is_selected = BooleanProperty(False)
    file_info = StringProperty('')
    
    def __init__(self, **kwargs):
        super(FileItem, self).__init__(**kwargs)
        self.cols = 1
        self.size_hint_y = None
        self.height = 120
        self.spacing = 5
        self.padding = 10
        self.create_content()
    
    def create_content(self):
        # 文件名称标签
        self.name_label = Label(
            text=self.file_name, 
            font_size=16, 
            halign='left',
            valign='middle',
            size_hint_y=None,
            height=30,
            text_size=(Window.width - 40, None)
        )
        # 文件信息标签
        self.info_label = Label(
            text=self.file_info, 
            font_size=12, 
            color=(0.5, 0.5, 0.5, 1),
            halign='left',
            valign='middle',
            size_hint_y=None,
            height=30,
            text_size=(Window.width - 40, None)
        )
        # 文件路径标签
        self.path_label = Label(
            text=self.file_path, 
            font_size=10, 
            color=(0.3, 0.3, 0.3, 1),
            halign='left',
            valign='middle',
            size_hint_y=None,
            height=40,
            text_size=(Window.width - 40, None)
        )
        
        self.add_widget(self.name_label)
        self.add_widget(self.info_label)
        self.add_widget(self.path_label)
    
    def refresh_view_attrs(self, rv, index, data):
        """刷新视图属性"""
        self.index = index
        self.file_name = data.get('file_name', '')
        self.file_path = data.get('file_path', '')
        self.file_size = data.get('file_size', '')
        self.file_date = data.get('file_date', '')
        self.file_info = f"大小: {self.file_size} | 修改日期: {self.file_date}"
        
        # 更新标签文本
        self.name_label.text = self.file_name
        self.info_label.text = self.file_info
        self.path_label.text = self.file_path
        
        return super(FileItem, self).refresh_view_attrs(rv, index, data)
    
    def on_touch_down(self, touch):
        """处理触摸事件"""
        if self.collide_point(*touch.pos):
            # 选择当前项
            self.select()
            # 显示上下文菜单
            app = App.get_running_app()
            if hasattr(app, 'show_context_menu'):
                app.show_context_menu(self.file_path)
            return True
        return super(FileItem, self).on_touch_down(touch)
    
    def select(self):
        """选择当前项"""
        if self.index is not None:
            self.parent.parent.select_item(self.index)

# 定义文件列表视图
class FileList(RecycleView):
    def __init__(self, **kwargs):
        super(FileList, self).__init__(**kwargs)
        self.data = []
        self.selected_index = None
        
        # 设置布局
        self.viewclass = 'FileItem'
        self.size_hint = (1, 1)
        self.do_scroll_x = False
        self.do_scroll_y = True
    
    def select_item(self, index):
        """选择指定索引的项"""
        if 0 <= index < len(self.data):
            self.selected_index = index
            # 更新UI以突出显示选中项
    
    def add_file(self, file_info):
        """添加文件到列表"""
        self.data.append({
            'file_name': file_info['name'],
            'file_path': file_info['path'],
            'file_size': file_info['size'],
            'file_date': file_info['date']
        })
    
    def clear_list(self):
        """清空列表"""
        self.data = []

# 文件扫描线程
class ScanThread(threading.Thread):
    def __init__(self, root_dir, file_types, app, **kwargs):
        super(ScanThread, self).__init__(**kwargs)
        self.root_dir = root_dir
        self.file_types = file_types
        self.app = app
        self._stop_event = threading.Event()
        self.total_count = 0
        self.current_count = 0
    
    def stop(self):
        """停止扫描"""
        self._stop_event.set()
    
    def is_stopped(self):
        """检查是否已停止"""
        return self._stop_event.is_set()
    
    def run(self):
        """开始扫描"""
        try:
            self.scan_directory(self.root_dir)
        except Exception as e:
            Clock.schedule_once(lambda dt: self.app.update_status(f"扫描出错: {str(e)}"), 0)
        finally:
            Clock.schedule_once(lambda dt: self.app.scan_completed(), 0)
    
    def scan_directory(self, directory):
        """扫描目录"""
        if self.is_stopped():
            return
        
        try:
            entries = os.listdir(directory)
            for entry in entries:
                if self.is_stopped():
                    return
                
                path = os.path.join(directory, entry)
                try:
                    if os.path.isfile(path):
                        ext = os.path.splitext(entry)[1].lower()
                        if not self.file_types or ext in self.file_types:
                            size = self.get_file_size(path)
                            date = self.get_file_date(path)
                            
                            file_info = {
                                'name': entry,
                                'path': path,
                                'size': size,
                                'date': date
                            }
                            
                            Clock.schedule_once(lambda dt, info=file_info: self.app.add_file_to_list(info), 0)
                            self.current_count += 1
                            Clock.schedule_once(lambda dt: self.app.update_status(f"扫描中... {self.current_count}"), 0)
                    elif os.path.isdir(path):
                        self.scan_directory(path)
                except (PermissionError, OSError):
                    # 忽略无权限访问的文件或目录
                    continue
        except (PermissionError, OSError):
            # 忽略无权限访问的目录
            pass
    
    def get_file_size(self, file_path):
        """获取文件大小"""
        try:
            size = os.path.getsize(file_path)
            if size < 1024:
                return f"{size} B"
            elif size < 1024 * 1024:
                return f"{size/1024:.2f} KB"
            elif size < 1024 * 1024 * 1024:
                return f"{size/(1024*1024):.2f} MB"
            else:
                return f"{size/(1024*1024*1024):.2f} GB"
        except:
            return "未知"
    
    def get_file_date(self, file_path):
        """获取文件修改日期"""
        try:
            mtime = os.path.getmtime(file_path)
            return datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
        except:
            return "未知"

# 主应用类
class iOSFileScannerApp(App):
    def __init__(self, **kwargs):
        super(iOSFileScannerApp, self).__init__(**kwargs)
        self.scan_thread = None
        self.file_list = None
        self.current_filter = ""
        self.file_types = []
        self.setup_database()
    
    def build(self):
        """构建UI"""
        self.root = BoxLayout(orientation='vertical', spacing=10, padding=10)
        self.create_ui()
        return self.root
    
    def create_ui(self):
        """创建用户界面"""
        # 标题标签
        title_label = Label(text="iOS文件扫描工具", font_size=20, size_hint_y=None, height=50)
        self.root.add_widget(title_label)
        
        # 控制区域
        control_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=50)
        
        # 扫描按钮
        self.scan_button = Button(text="扫描", size_hint_x=0.4)
        self.scan_button.bind(on_press=self.start_scan)
        control_layout.add_widget(self.scan_button)
        
        # 停止按钮
        self.stop_button = Button(text="停止", size_hint_x=0.3)
        self.stop_button.bind(on_press=self.stop_scan)
        control_layout.add_widget(self.stop_button)
        
        # 文件类型按钮
        self.type_button = Button(text="文件类型", size_hint_x=0.3)
        self.type_button.bind(on_press=self.show_file_types)
        control_layout.add_widget(self.type_button)
        
        self.root.add_widget(control_layout)
        
        # 搜索框
        self.search_input = TextInput(
            hint_text="搜索文件名...", 
            size_hint_y=None, 
            height=40,
            multiline=False
        )
        self.search_input.bind(text=self.on_search_text)
        self.root.add_widget(self.search_input)
        
        # 文件列表
        self.file_list = FileList()
        self.root.add_widget(self.file_list)
        
        # 状态栏
        self.status_label = Label(text="就绪", size_hint_y=None, height=30, color=(0.5, 0.5, 0.5, 1))
        self.root.add_widget(self.status_label)
    
    def setup_database(self):
        """设置SQLite数据库"""
        try:
            # 在iOS上使用应用文档目录存储数据库
            if platform.system() == 'Darwin':  # iOS和macOS
                from kivy.app import platform
                if platform == 'ios':
                    db_path = os.path.join(os.path.expanduser('~'), 'Documents', 'file_notes.db')
                else:
                    db_path = 'file_notes.db'
            else:
                db_path = 'file_notes.db'
                
            self.conn = sqlite3.connect(db_path)
            self.cursor = self.conn.cursor()
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS file_notes (
                    file_path TEXT PRIMARY KEY,
                    note TEXT,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            ''')
            self.conn.commit()
        except Exception as e:
            print(f"数据库设置错误: {str(e)}")
    
    def start_scan(self, instance):
        """开始扫描"""
        # 在iOS上，使用文件选择器让用户选择扫描目录
        self.show_directory_picker()
    
    def show_directory_picker(self):
        """显示目录选择器"""
        try:
            # 在iOS上使用plyer的文件选择器
            def on_selection(results):
                if results:
                    directory = results[0]
                    self.file_list.clear_list()
                    self.update_status("开始扫描...")
                    
                    # 创建并启动扫描线程
                    if self.scan_thread and self.scan_thread.is_alive():
                        self.scan_thread.stop()
                        self.scan_thread.join()
                    
                    self.scan_thread = ScanThread(directory, self.file_types, self)
                    self.scan_thread.daemon = True
                    self.scan_thread.start()
                    
                    # 更新按钮状态
                    self.scan_button.disabled = True
                    self.stop_button.disabled = False
            
            filechooser.choose_dir(on_selection=on_selection)
        except Exception as e:
            self.update_status(f"选择目录错误: {str(e)}")
    
    def stop_scan(self, instance):
        """停止扫描"""
        if self.scan_thread and self.scan_thread.is_alive():
            self.scan_thread.stop()
            self.scan_thread.join(2)
            self.update_status("扫描已停止")
            self.scan_completed()
    
    def scan_completed(self):
        """扫描完成"""
        self.scan_button.disabled = False
        self.stop_button.disabled = True
        self.update_status(f"扫描完成，找到 {len(self.file_list.data)} 个文件")
    
    def add_file_to_list(self, file_info):
        """添加文件到列表"""
        # 应用搜索过滤
        if not self.current_filter or self.current_filter.lower() in file_info['name'].lower():
            self.file_list.add_file(file_info)
    
    def on_search_text(self, instance, value):
        """处理搜索文本变化"""
        self.current_filter = value
        # 重新过滤列表
        self.apply_filter()
    
    def apply_filter(self):
        """应用过滤器"""
        # 这里简化处理，实际应用中可以维护原始数据并过滤显示
        pass
    
    def update_status(self, message):
        """更新状态栏消息"""
        self.status_label.text = message
    
    def show_file_types(self, instance):
        """显示文件类型选择器"""
        popup = Popup(title="选择文件类型", size_hint=(0.9, 0.8))
        
        layout = BoxLayout(orientation='vertical', padding=10, spacing=10)
        scroll = ScrollView()
        
        # 预定义的文件类型
        common_types = [
            ".jpg", ".jpeg", ".png", ".gif", ".bmp",  # 图片
            ".mp3", ".wav", ".flac", ".aac", ".ogg",  # 音频
            ".mp4", ".avi", ".mov", ".mkv", ".flv",  # 视频
            ".doc", ".docx", ".pdf", ".txt", ".rtf",  # 文档
            ".xls", ".xlsx", ".csv",  # 表格
            ".zip", ".rar", ".7z", ".tar", ".gz"  # 压缩文件
        ]
        
        type_checkboxes = []
        checkbox_layout = GridLayout(cols=2, spacing=5, size_hint_y=None)
        checkbox_layout.bind(minimum_height=checkbox_layout.setter('height'))
        
        for file_type in common_types:
            checkbox_row = BoxLayout(orientation='horizontal', size_hint_y=None, height=40)
            checkbox = CheckBox(size_hint_x=0.2)
            label = Label(text=file_type, size_hint_x=0.8, halign='left', valign='middle')
            
            # 如果已在选择列表中，设置为选中
            if file_type in self.file_types:
                checkbox.active = True
            
            checkbox.bind(active=lambda instance, value=file_type: self.toggle_file_type(value, instance.active))
            checkbox_row.add_widget(checkbox)
            checkbox_row.add_widget(label)
            checkbox_layout.add_widget(checkbox_row)
        
        scroll.add_widget(checkbox_layout)
        layout.add_widget(scroll)
        
        # 关闭按钮
        close_button = Button(text="关闭", size_hint_y=None, height=50)
        close_button.bind(on_press=popup.dismiss)
        layout.add_widget(close_button)
        
        popup.content = layout
        popup.open()
    
    def toggle_file_type(self, file_type, is_active):
        """切换文件类型选择状态"""
        if is_active:
            if file_type not in self.file_types:
                self.file_types.append(file_type)
        else:
            if file_type in self.file_types:
                self.file_types.remove(file_type)
    
    def show_context_menu(self, file_path):
        """显示上下文菜单"""
        popup = Popup(title="文件操作", size_hint=(0.8, 0.4))
        
        layout = GridLayout(cols=1, spacing=5, padding=10)
        
        # 菜单项按钮
        menu_items = [
            ("打开文件", lambda: self.open_file(file_path)),
            ("添加/编辑备注", lambda: self.add_note(file_path)),
            ("复制文件路径", lambda: self.copy_file_path(file_path)),
            ("复制到自定义文件夹", lambda: self.copy_file(file_path)),
            ("文件改名", lambda: self.rename_file(file_path)),
            ("删除文件", lambda: self.delete_file(file_path))
        ]
        
        for text, callback in menu_items:
            button = Button(text=text, size_hint_y=None, height=40)
            button.bind(on_press=lambda instance, cb=callback, p=popup: [cb(), p.dismiss()])
            layout.add_widget(button)
        
        popup.content = layout
        popup.open()
    
    def open_file(self, file_path):
        """打开文件"""
        try:
            if platform.system() == 'Darwin':  # iOS和macOS
                # 在iOS上使用plyer打开文件
                from plyer import filechooser
                # 使用系统默认应用打开文件
                import subprocess
                # 在iOS上，使用open命令打开文件
                subprocess.call(['open', file_path])
            else:
                os.startfile(file_path)
        except Exception as e:
            self.update_status(f"打开文件错误: {str(e)}")
    
    def copy_file_path(self, file_path):
        """复制文件路径到剪贴板"""
        try:
            clipboard.copy(file_path)
            self.update_status("文件路径已复制到剪贴板")
        except Exception as e:
            self.update_status(f"复制错误: {str(e)}")
    
    def add_note(self, file_path):
        """添加/编辑备注"""
        # 查询是否已有备注
        try:
            self.cursor.execute("SELECT note FROM file_notes WHERE file_path = ?", (file_path,))
            result = self.cursor.fetchone()
            existing_note = result[0] if result else ""
            
            # 创建备注编辑弹窗
            popup = Popup(title="添加/编辑备注", size_hint=(0.9, 0.6))
            
            layout = BoxLayout(orientation='vertical', padding=10, spacing=10)
            
            # 文件路径标签
            path_label = Label(text=file_path, size_hint_y=None, height=40, halign='left', valign='middle')
            layout.add_widget(path_label)
            
            # 备注输入框
            note_input = TextInput(text=existing_note, multiline=True, hint_text="请输入备注...")
            layout.add_widget(note_input)
            
            # 保存按钮
            def save_note():
                note_text = note_input.text
                try:
                    if existing_note:
                        # 更新备注
                        self.cursor.execute(
                            "UPDATE file_notes SET note = ?, updated_at = CURRENT_TIMESTAMP WHERE file_path = ?",
                            (note_text, file_path)
                        )
                    else:
                        # 插入新备注
                        self.cursor.execute(
                            "INSERT INTO file_notes (file_path, note) VALUES (?, ?)",
                            (file_path, note_text)
                        )
                    self.conn.commit()
                    self.update_status("备注已保存")
                    popup.dismiss()
                except Exception as e:
                    self.update_status(f"保存备注错误: {str(e)}")
            
            button_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=50)
            save_button = Button(text="保存")
            save_button.bind(on_press=lambda x: save_note())
            cancel_button = Button(text="取消")
            cancel_button.bind(on_press=popup.dismiss)
            
            button_layout.add_widget(save_button)
            button_layout.add_widget(cancel_button)
            layout.add_widget(button_layout)
            
            popup.content = layout
            popup.open()
        except Exception as e:
            self.update_status(f"加载备注错误: {str(e)}")
    
    def copy_file(self, file_path):
        """复制到自定义文件夹"""
        try:
            def on_destination_select(results):
                if results:
                    destination = results[0]
                    try:
                        # 如果目标是目录，使用原文件名
                        if os.path.isdir(destination):
                            file_name = os.path.basename(file_path)
                            destination_path = os.path.join(destination, file_name)
                        else:
                            destination_path = destination
                        
                        # 复制文件
                        shutil.copy2(file_path, destination_path)
                        self.update_status(f"文件已复制到: {destination_path}")
                    except Exception as e:
                        self.update_status(f"复制文件错误: {str(e)}")
            
            # 显示文件保存对话框
            filechooser.save_file(on_selection=on_destination_select)
        except Exception as e:
            self.update_status(f"选择目标错误: {str(e)}")
    
    def rename_file(self, file_path):
        """文件改名"""
        try:
            # 创建重命名弹窗
            popup = Popup(title="文件改名", size_hint=(0.8, 0.4))
            
            layout = BoxLayout(orientation='vertical', padding=10, spacing=10)
            
            # 当前文件路径
            path_label = Label(text=f"当前文件: {file_path}", size_hint_y=None, height=40)
            layout.add_widget(path_label)
            
            # 新文件名输入
            current_name = os.path.basename(file_path)
            name_input = TextInput(text=current_name, multiline=False)
            layout.add_widget(name_input)
            
            # 按钮布局
            button_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=50)
            
            # 确认按钮
            def confirm_rename():
                new_name = name_input.text
                if new_name and new_name != current_name:
                    try:
                        directory = os.path.dirname(file_path)
                        new_path = os.path.join(directory, new_name)
                        os.rename(file_path, new_path)
                        self.update_status(f"文件已重命名为: {new_name}")
                        popup.dismiss()
                    except Exception as e:
                        self.update_status(f"重命名错误: {str(e)}")
                else:
                    popup.dismiss()
            
            confirm_button = Button(text="确认")
            confirm_button.bind(on_press=lambda x: confirm_rename())
            cancel_button = Button(text="取消")
            cancel_button.bind(on_press=popup.dismiss)
            
            button_layout.add_widget(confirm_button)
            button_layout.add_widget(cancel_button)
            layout.add_widget(button_layout)
            
            popup.content = layout
            popup.open()
        except Exception as e:
            self.update_status(f"重命名错误: {str(e)}")
    
    def delete_file(self, file_path):
        """删除文件"""
        try:
            # 创建确认弹窗
            popup = Popup(title="确认删除", size_hint=(0.7, 0.3))
            
            layout = BoxLayout(orientation='vertical', padding=10, spacing=10)
            
            # 提示信息
            message = Label(text=f"确定要删除文件\n{os.path.basename(file_path)}吗？", halign='center', valign='middle')
            layout.add_widget(message)
            
            # 按钮布局
            button_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=40)
            
            # 确认删除
            def confirm_delete():
                try:
                    os.remove(file_path)
                    self.update_status(f"文件已删除: {os.path.basename(file_path)}")
                    popup.dismiss()
                except Exception as e:
                    self.update_status(f"删除错误: {str(e)}")
            
            delete_button = Button(text="删除", background_color=(1, 0, 0, 1))
            delete_button.bind(on_press=lambda x: confirm_delete())
            cancel_button = Button(text="取消")
            cancel_button.bind(on_press=popup.dismiss)
            
            button_layout.add_widget(delete_button)
            button_layout.add_widget(cancel_button)
            layout.add_widget(button_layout)
            
            popup.content = layout
            popup.open()
        except Exception as e:
            self.update_status(f"删除错误: {str(e)}")
    
    def on_stop(self):
        """应用关闭时的清理"""
        # 停止扫描线程
        if self.scan_thread and self.scan_thread.is_alive():
            self.scan_thread.stop()
            self.scan_thread.join(2)
        
        # 关闭数据库连接
        if hasattr(self, 'conn'):
            self.conn.close()

if __name__ == '__main__':
    # 启动应用
    iOSFileScannerApp().run()